<template>
  <div class="formatter-container">
    选中配置文本后按下Enter可直接进行查询 | 点击"格式化"可消除空格和替换中文符号 | Ctrl+L清除查询记录 | 缺失的括号会红色高亮<br><br>
    <div class="input-group">
      <div class="editable-input" contenteditable="true" @input="handleInput" @click="handleCursorMove"
        @keyup="handleCursorMove" @keydown.enter.prevent="handleEnter" @keydown.ctrl.l.prevent="clearResults"
        ref="inputRef"></div>
      <el-button type="primary" @click="formatContent">格式化</el-button>
    </div>

    <!-- 搜索结果展示区域 -->
    <div v-if="searchResults.length > 0" class="search-results">
      <div v-for="(result, index) in searchResults" :key="result.id" class="result-item">
        <div class="result-close" @click="removeResult(index)">×</div>
        <div class="result-header">
          <div class="result-info">
            <span class="result-id">ID: {{ result.id }}</span>
            <span class="result-type">类型: {{ result.type_str }}</span>
          </div>
        </div>
        <div class="result-content">
          <div class="result-desc" v-html="highlightDesc(result.desc)"></div>
          <div v-if="result.note" class="result-note">备注: {{ result.note }}</div>
          <!-- 每个结果都有自己的替换内容 -->
          <div v-if="replacedContents[index]" class="replaced-content">
            <div class="replaced-title">参数替理结果:</div>
            <div class="original-text">配置原文: {{ replacedOriContents[index] }}</div>
            <div class="replaced-text" v-html="replacedContents[index]"></div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted } from 'vue'
import axios from 'axios'
import type { Ref } from 'vue'
import { ElMessage } from 'element-plus'
import { ES_CONFIG, type SearchResponse } from '@/config/elasticsearch'
import { type CombatScriptDocument } from './CombatScriptRepDO'
import { findMatchBracket, highlightStyleGen, BRACKETS, RECEIVE_BRACKETS, findMatchBracketBack, globalBracketAnalyze, defaultHighlightStyleGen } from './CombatScriptText'

// 使用通用的文档接口
type SearchResult = CombatScriptDocument

// 组件状态变量
const content: Ref<string> = ref('')  // 用于存储纯文本内容
const inputRef = ref<HTMLElement | null>(null)
const searchResults = ref<SearchResult[]>([])  // 搜索结果列表
const selectedText = ref('')
const replacedOriContents = ref<string[]>([])
const replacedBeforeDesc = ref('')
const replacedContents = ref<string[]>([])  // 改为数组存储每个结果的替换内

// 括号配对映射表
const bracketPairs = BRACKETS;

/**
 * 处理键盘按键事件，实现括号高亮功能
 * @param e 键盘事件对象
 */
const handleInput = (e: Event): void => {
  const target = e.target as HTMLElement
  content.value = target.innerText
  handleCursorMove()
}

/**
 * 解析并替换参数
 * @param text 原始文本
 * @param searchId 搜索的ID
 * @param descriptions 描述文本数组
 * @returns [替换后的文本数组, 原始配置文本]
 */
const replaceParameters = (text: string, searchId: string, descriptions: string[]): [string[], string] => {
  // example: {1243,[{[10030],[{9,2}]}]},{1233,[[10020,10021],[10030],700]},{8000,[1,2,3]}
  // 获得searchId在text的置
  const searchIdPos = text.indexOf(searchId)
  const searchIdBeginPos = searchIdPos;
  // 参数列表的括号
  const argsBracketCloseChar = ']';
  const argsBracketOpenChar = '[';
  let argsBracketCount = 1;
  // 从searchIdBeginPos开始找到第一个 '['
  let i = searchIdBeginPos;
  for (i = searchIdBeginPos; i < text.length; i++) {
    if (text.charAt(i) === argsBracketOpenChar) {
      break;
    }
  }

  // 提取参数值列表
  const paramValues: string[] = []
  let currentValue = ''
  let bracketCount = 0

  // 参数括号边界
  while (i < text.length) {

    let j = i + 1;
    while (j < text.length) {
      const char = text[j];
      if (char === argsBracketOpenChar) argsBracketCount++;
      if (char === argsBracketCloseChar) argsBracketCount--;
      if (argsBracketCount === 0) break;
      // 判断char是否在bracketPairs中
      if (Object.keys(bracketPairs).includes(char)) {
        // 找到对应的右括号
        bracketCount = 1;
        let z = j + 1;
        while (z < text.length && bracketCount > 0) {
          // 判断char的闭括号
          if (text[z] === char) bracketCount++;
          if (text[z] === bracketPairs[char]) bracketCount--;
          z++;
        }
        if (text[z - 1] === argsBracketCloseChar) argsBracketCount--;
        // 提取包含号的完整内容
        currentValue += text.substring(j, z);
        j = z;
      } else if (char === ',' && bracketCount === 0) {
        paramValues.push(currentValue.trim());
        currentValue = '';
        j++;
      } else {
        let z = j + 1;
        let char = text[z];
        while (z < text.length && (char !== ',' && !Object.values(bracketPairs).includes(char))) {
          z++;
          char = text[z];
        }
        currentValue += text.substring(j, z);
        j = z;
      }
    }
    i = j;
    if (argsBracketCount === 0) break;
  }

  if (currentValue) {
    paramValues.push(currentValue.trim());
  }

  const oriContent = `{${searchId},[${paramValues.join(',')}]}`;
  //   replacedOriContent.value = paramValues.join(',');
  // console.log('paramValues:', paramValues);

  // 对每个描述文本进行替换
  return [descriptions.map(description => {
    let result = description;
    paramValues.forEach((value, index) => {
      // 使用更精确的正则表达式，添加\b表示单词边界，避免误匹配值10中的值1等情况
      const valuePattern = new RegExp(`值${index + 1}\\b`, 'g');
      // 添加间距并用 span 包裹替换的值以便添加样式
      result = result.replace(valuePattern, ` <span class="replaced-value">${value}</span> `);
    });
    return result;
  }), oriContent];
}

/**
 * 处理回车事件，执行搜索功能
 */
const handleEnter = async (): Promise<void> => {
  if (!inputRef.value) return

  const selection = window.getSelection()
  if (!selection || !selection.rangeCount) return

  const range = selection.getRangeAt(0)
  const selectedText = range.toString().trim()

  if (!selectedText) return

  try {
    const response = await axios.post<SearchResponse<SearchResult>>(
      `${ES_CONFIG.baseUrl}/${ES_CONFIG.indices.scriptDocs}/_search`,
      {
        track_total_hits: true,
        query: {
          term: {
            id: selectedText
          }
        }
      },
      {
        withCredentials: false,
        headers: {
          'Content-Type': 'application/json'
        }
      }
    )

    // 将新结果添加到现有结果列表的最前面
    const newResults = response.data.hits.hits.map((hit: { _source: SearchResult }) => hit._source)
    searchResults.value = [...newResults, ...searchResults.value]

    // 为新结果执行参数替换
    if (newResults.length > 0) {
      const descriptions = newResults.map(result => result.desc)
      const [newReplacedContents, oriContent] = replaceParameters(
        content.value,
        selectedText,
        descriptions
      )

      // 将新的替换内容和原始内容添加到现有数组的最前面
      replacedContents.value = [
        ...newReplacedContents,
        ...replacedContents.value
      ]
      
      // 将新的原始配置内容添加到数组
      replacedOriContents.value = [
        ...Array(newReplacedContents.length).fill(oriContent),
        ...replacedOriContents.value
      ]
    }
  } catch (error) {
    console.error('搜索失败:', error)
    ElMessage.error('搜索失败，请稍后试')
  }
}

// 添加移除单个结果的函数
const removeResult = (index: number): void => {
  searchResults.value.splice(index, 1)
  replacedContents.value.splice(index, 1)
  replacedOriContents.value.splice(index, 1)
}

// 处理光标移动
const handleCursorMove = (): void => {
  if (!inputRef.value) return

  const selection = window.getSelection()
  if (!selection || !selection.rangeCount) return

  // 获取原始文本（不包含HTML标签）
  const plainText = inputRef.value.innerText

  const range = selection.getRangeAt(0)
  
  // 计算真实的开始和结束位置
  function calculateRealPosition(node: Node, targetNode: Node, targetOffset: number): number {
    let position = 0
    
    function traverse(currentNode: Node): number {
      if (currentNode === targetNode) {
        return position + targetOffset
      }

      if (currentNode.nodeType === Node.TEXT_NODE) {
        position += currentNode.textContent?.length || 0
      }

      for (const child of Array.from(currentNode.childNodes)) {
        const result = traverse(child)
        if (result !== -1) return result
      }

      return -1
    }

    return traverse(node)
  }

  // 获取选择的开始和结束位置
  const startPos = calculateRealPosition(inputRef.value, range.startContainer, range.startOffset)
  const endPos = calculateRealPosition(inputRef.value, range.endContainer, range.endOffset)

  // 清除现有的高亮
  const existingHighlights = inputRef.value.querySelectorAll('.bracket-highlight')
  existingHighlights.forEach(el => {
    const parent = el.parentNode
    if (parent) {
      parent.replaceChild(document.createTextNode(el.textContent || ''), el)
    }
  })
  
  const pos = globalBracketAnalyze(plainText)
  if (pos > -1) {
    // 高亮第一个不匹配的括号
    if (inputRef.value) {
      inputRef.value.innerHTML = highlightStyleGen(plainText, pos, pos, 'red') || ""
    }
  }

  // 使用原始文本和真实位置检查括号
  const prevChar = plainText[startPos - 1]
  const currentChar = plainText[startPos]

  let highlightTextStartPos = -1
  let highlightTextEndPos = -1

  if (prevChar && Object.keys(bracketPairs).includes(prevChar)) {
    const matchPos = findMatchBracket(plainText, startPos - 1)
    highlightTextStartPos = startPos - 1
    highlightTextEndPos = matchPos
  } else if (currentChar && Object.keys(RECEIVE_BRACKETS).includes(currentChar)) {
    const matchPos = findMatchBracketBack(plainText, startPos)
    highlightTextStartPos = matchPos
    highlightTextEndPos = startPos
  }

  const result = defaultHighlightStyleGen(plainText, highlightTextStartPos, highlightTextEndPos)
  if (result) {
    inputRef.value.innerHTML = result
  }
  // {8613,[[70040,70041],[{2,70040,1016,[{1,3,70161}]},{2,70041,1016,[{1,3,70161}]}]]}
  // 恢复选择状态
  if (startPos > -1 || endPos > -1) {
    const newRange = document.createRange()
    let currentPos = 0
    let startNode: Node | null = null
    let startOffset = 0
    let endNode: Node | null = null
    let endOffset = 0

    function findNodeForPosition(node: Node, targetPos: number): boolean {
      if (node.nodeType === Node.TEXT_NODE) {
        const length = node.textContent?.length || 0
        if (currentPos + length >= targetPos) {
          if (!startNode) {
            startNode = node
            startOffset = targetPos - currentPos
          } else {
            endNode = node
            endOffset = targetPos - currentPos
          }
          return true
        }
        currentPos += length
      } else {
        for (const child of Array.from(node.childNodes)) {
          if (findNodeForPosition(child, targetPos)) return true
        }
      }
      return false
    }

    // 找到开始位置
    findNodeForPosition(inputRef.value, startPos)
    // 重置 currentPos 并找到结束位置
    currentPos = 0
    findNodeForPosition(inputRef.value, endPos)

    if (startNode && endNode) {
      newRange.setStart(startNode, startOffset)
      newRange.setEnd(endNode, endOffset)
      selection.removeAllRanges()
      selection.addRange(newRange)
    }
  }
  console.log("--------------------------------");
} 

// 添加格式化函数
const formatContent = () => {
  if (!inputRef.value) return

  const text = inputRef.value.innerText
    .replace(/\s+/g, '')  // 移除所有空格
    .replace(/，/g, ',')  // 替换中文逗号
    .replace(/：/g, ':')  // 替换中文冒号

  inputRef.value.innerText = text
  content.value = text
}

const clearResults = (): void => {
  searchResults.value = []
  replacedContents.value = []
  replacedOriContents.value = []
  replacedBeforeDesc.value = ''
}

const highlightDesc = (desc: string) => {
  return desc.replace(/列表/g, '<span class="highlight-keyword">列表</span>')
}
</script>

<style scoped>
/* 器样式 */
.formatter-container {
  padding: 20px;
}

/* 搜索结果区域样式 */
.search-results {
  margin-top: 20px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

/* 结果项样式 */
.result-item {
  border: 1px solid #dcdfe6;
  border-radius: 4px;
  padding: 12px 16px;
  background-color: #fff;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
  position: relative;
}

.result-header {
  display: flex;
  margin-bottom: 8px;
  padding-right: 24px;
  /* 为关闭按钮留出空间 */
}

.result-info {
  display: flex;
  gap: 16px;
  /* ID和类型之间的间距 */
  flex: 1;
}

.result-id {
  font-weight: bold;
  color: #409EFF;
}

.result-type {
  color: #67c23a;
}

.result-content {
  font-size: 14px;
}

.result-desc {
  color: #303133;
  line-height: 1.5;
  margin-bottom: 4px;
}

.result-note {
  color: #909399;
  font-size: 13px;
}

/* 添加参数替换相关样式 */
.replaced-content {
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px dashed #dcdfe6;
}

.replaced-title {
  font-weight: bold;
  color: #409EFF;
  margin-bottom: 8px;
}

.original-text,
.replaced-text {
  font-family: monospace;
  white-space: pre-wrap;
  word-break: break-all;
  padding: 4px 8px;
  background-color: #f5f7fa;
  border-radius: 4px;
  margin-bottom: 4px;
}

.replaced-text {
  color: #67c23a;
}

/* 添加这个式确保高亮效果可见 */
.el-input {
  position: relative;
}

/* 在 style 部分添加以下样 */
:deep(.replaced-value) {
  background-color: #ecf5ff;
  color: red;
  padding: 0 6px;
  margin: 0 2px;
  border-radius: 3px;
  display: inline-block;
}

.replaced-text {
  color: #67c23a;
}

/* 由于我们现在返回的文本包含 HTML，需要允许 HTML 渲染 */
.result-content {
  font-size: 14px;
}

.result-desc {
  color: #303133;
  line-height: 1.5;
  margin-bottom: 4px;
}

/* 确保输入框容器是相对定位 */
:deep(.el-input) {
  position: relative;
}

/* 输入框样式调整 */
:deep(.el-input__inner) {
  font-family: monospace;
  white-space: pre;
  position: relative;
  z-index: 1;
}

/* 高亮动画效果 */
:deep(.bracket-highlight) {
  animation: fadeIn 0.2s ease-in-out;
}

@keyframes fadeIn {
  from {
    opacity: 0;
  }

  to {
    opacity: 1;
  }
}

/* 添加结果项的关闭按钮样式 */
.result-close {
  position: absolute;
  top: 12px;
  right: 12px;
  width: 20px;
  height: 20px;
  line-height: 18px;
  /* 稍微调整以使 × 垂直居中 */
  text-align: center;
  cursor: pointer;
  color: #909399;
  font-size: 16px;
  border-radius: 50%;
  transition: all 0.3s;
  background-color: transparent;
}

.result-close:hover {
  background-color: #f56c6c;
  color: white;
}

/* 确保结果项有足够的内边距 */
.result-item {
  position: relative;
  padding: 12px 16px;
}

/* 添加输入组样式 */
.input-group {
  display: flex;
  gap: 10px;
  align-items: flex-start;
}

.input-group .el-input {
  flex: 1;
}

/* 在 style 部分添加 */
:deep(.highlight-keyword) {
  background-color: #ffd04b;
  padding: 0 4px;
  border-radius: 3px;
  font-weight: bold;
}

/* 修改可编辑输入框样式 */
.editable-input {
  min-height: 40px;
  padding: 12px 16px;
  /* 增加内边距 */
  border: 1px solid #dcdfe6;
  border-radius: 4px;
  background-color: #fff;
  font-family: monospace;
  font-size: 15px;
  /* 增加字体大小 */
  line-height: 1.8;
  /* 增加行高 */
  letter-spacing: 1px;
  /* 添加字母间距 */
  flex: 1;
  white-space: pre-wrap;
  word-break: break-all;
  outline: none;
  transition: border-color 0.2s;
}

.editable-input:focus {
  border-color: #409eff;
}

.editable-input:empty::before {
  content: '请输入配置文本';
  color: #999;
  font-size: 15px;
  /* 占位符文字大小也相应调整 */
}

/* 括号高亮样式 */
.bracket-highlight {
  background-color: rgba(64, 158, 255, 0.2);
  border: 1px solid #409EFF;
  border-radius: 2px;
  padding: 0 2px;
  margin: 0 1px;
}
</style>
